<?php 
/**
 * Main Pjq Class
 *
 * @author Richard Thomas <lists@cyberlot.net>
 * @version 0.1
 * @package pjq
 * @subpackage main
 * @copyright Copyright &copy; 2007, Richard Thomas
 */


/**
 * Pjq Class
 */
 
class Pjq {
  /**
   * What formats can we direct process, request handled directly
   * are not handled by the request object, they are just returned as is.
   * @access private
   * @var array
   */
  var $directFormats = array('json', 'xml', 'html');

  /**
   * How do we valide callbacks so no funny stuff is tried
   * 0 - No validation: Not suggested for use, could leave things open
   * 1 - Validate against an array of possible class base names
   * 2 - Only allow registered callback methods and classes PREFERRED!
   * @access private
   * @var array
   */ 
  var $validateCallbacks = 2;

  /**
   * What are the valid base class and method names?
   * @access private
   * @var array
   */
  var $callbackFilter = array('Pjq');

  /**
   * Array of all registered methods
   * @access private
   * @var array
   */
  var $registered_methods = array();

  /**
   * Array of all registered objects
   * @access private
   * @var array
   */
  var $registered_objects = array();
  
  /**
   * Handle incoming data, verify callback and either getData or build the response
   * 
   */
  function processIncoming() {
    if($this->validateCallbacks AND !$this->validateCallback($_REQUEST['callback'])) {
      return false;
    }
    // Here we check the handler to see if we have a direct Format request, in this case we return that
    // formatted data directly
    if(isset($_REQUEST['handler']) AND in_array($_REQUEST['handler'], $this->directFormats)) {
      $data = $this->getData($_REQUEST['callback'],$this->getParams(), $_REQUEST['handler']);
    } else {
      require_once('Pjq_Response.php');
      $responseObject = Pjq_Response::getInstance();
      $responseObject->processCallback($_REQUEST['callback'], $this->getParams());
      $data = $responseObject->getResponse();
    }
    if($data) {
      echo $data;
    }
  }


  /**
   * Handle incoming data, verify callback and either getData or build the response
   * 
   * @param string
   * @return booleon
   */
  function validateCallback($callback) {
    $valid = 0;
    switch($this->validateCallbacks) {
      case 1:
        /**
         * Only allow callbacks that match our "filter" base strings
         */
        $obj = is_array($callback);
        foreach($this->callbackFilter as $value) {
          if(($obj AND (strpos($callback[0], $value) !== false)) OR (!$obj AND (strpos($callback, $value) !== false))) {
            $valid = 1;
            break;
          } 
        }
      break;
      case 2:
        /**
         * We want to be strict, only allow registered callbacks
         */
        $obj = is_array($callback);
        if($obj) {
          if(isset($this->registered_objects[$callback[0]]) AND ((in_array($callback[1], $this->registered_objects[$callback[0]])) OR ($this->registered_objects[$callback[0]] === 1)) ) {
            $valid = 1;
            break;
          }
        } else {
          if(in_array($callback, $this->registered_methods)) {
            $valid = 1;
            break;
          }
        }
      break;
      default:
        /**
         * Any callback is valid
         */
        $valid = 1;
      break;
    }
    return $valid;
  }

  /**
   * Register our callback methods or specific method within an object
   * 
   * @param mixed
   */
  function registerCallback($callback) {
    if(is_array($callback)) {
      $this->registered_objects[$callback[0]] = $callback[1];
    } else {
      $this->registered_methods[] = $callback;
    }
  }

  /**
   * Register an object and all its methods
   * 
   * @param object
   */
  function registerObject($object) {
    $this->registered_objects[$object] = 1;
  }

  /**
   * Register a string as a base callback filter
   * 
   * @param string
   */
  function registerFilter($filter) {
    $this->callbackFilter[] = $filter;
  }

  /**
   * getData is for direct requests, no further handling of the response is done
   * 
   * @param mixed
   * @param array
   * @param string
   * @return mixed
   */
  function getData($callback, $params, $format = '') {
    $data = call_user_func_array($callback, $params);
    switch($format) {
      case 'json':
        $edata = json_encode($data);
      break;
      default:
        /**
         * Right now xml and html formats have to be handled by the user function
         * In the future there should be an xml encoder to allow easy changing between
         * json and xml
         */
        $edata = $data;
      break;
    }
    return $edata;
  }

  /**
   * We should prob do some sort of filtering here
   */
  function getParams() {
    $params = null;
    if(isset($_REQUEST['params'])) {
      $params = $_REQUEST['params'];
    }
    return $params;
  }

}